/**
 * @author ahammer
 * @date 2009
 */

/*
 * adapted from:
 * A utility class for obtaining a variety of image information.
 * @version 1.0  10 Feb 2000
 * @author Lawrence Rodrigues
 * http://my.execpc.com/~larryhr/
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tools;

import java.awt.*;
import java.awt.image.*;
import java.awt.color.*;


/** A utility class for obtaining a variety of image information.
 * @version 1.0  10 Feb 2000
 * @author Lawrence Rodrigues
 */
public class ImageInfoUtil {
	   public final static int RED = 0;
	   public final static int GREEN = 1;
	   public final static int BLUE = 2;
	   public final static int ALPHA = 3;

	   public final static int DIRECT = 0;
	   public final static int INDEX = 1;
	   public final static int COMPONENT = 2;

	   public final static int COMPONENT_SAMPLE = 0;
	   public final static int BANDED = 1;
	   public final static int PIXEL_INTERLEAVED = 2;
	   public final static int SINGLE_PIXEL_PACKED =3;
	   public final static int MULTI_PIXEL_PACKED = 4;


	   public static  String[][] getImageInfo(BufferedImage img) {
	      SampleModel sm = img.getSampleModel();
	      WritableRaster wr = img.getRaster();
	       DataBuffer db = wr.getDataBuffer();
	      ColorModel cm = img.getColorModel();
	      String str = getColorModelAsText(getColorModelType(cm));
	      ColorSpace cs = cm.getColorSpace();
	      String[][] rowData = new String[10][2];
	      int i =0;
	      rowData[i][0] = "Color Model";
	      rowData[i++][1] =  str;
	      rowData[i][0] = "Color space";
	      rowData[i++][1] = getColorSpaceAsText(cs.getType());

	      rowData[i][0] = "Sample Model";
	      rowData[i++][1] = getSampleModelAsText(getSampleModelType(sm));
	      //DataBuffer db = wr.getDataBuffer();
	      rowData[i][0] = "Data type";
	      rowData[i++][1] =  getDataTypeAsText(db.getDataType());
	      int numbands = sm.getNumBands();
	      rowData[i][0] = "Number of Bands";
	      rowData[i++][1] =  Integer.toString(numbands);
	      int numbanks = db.getNumBanks();
	      rowData[i][0] = "Number of Banks";
	      rowData[i++][1] =  Integer.toString(numbanks);

	      rowData[i][0] = "Width";

	      rowData[i++][1] = Integer.toString(img.getWidth());
	      rowData[i][0] = "Height";
	      rowData[i++][1] = Integer.toString(img.getHeight());
	      int scanlineStride=0;
	      if(sm instanceof ComponentSampleModel) {
	          ComponentSampleModel csm = (ComponentSampleModel)sm;
	          scanlineStride = csm.getScanlineStride();
	          rowData[i][0] = "Scanline stride";
	          rowData[i++][1] = Integer.toString(scanlineStride);
	          int pixelStride =   csm.getPixelStride();
	          rowData[i][0] = "Pixel stride";
	          rowData[i++][1] = Integer.toString(pixelStride);
	          //int[] bankIndices = csm.getBankIndices();
	          //System.out.println("bank indices = " );
	          //for(int j=0; j<bankIndices.length;j++)
	          //    System.out.println(bankIndices[j]);
	          //int[] bandOffsets = csm.getBandOffsets();
	          //System.out.println("bank offsets = " );
	          //for(int j=0; j<bandOffsets.length;j++)
	          //System.out.println(bandOffsets[j]);
	      } else {
	          if( sm  instanceof SinglePixelPackedSampleModel){
	              SinglePixelPackedSampleModel  ssm = (SinglePixelPackedSampleModel)sm;
	              scanlineStride = ssm.getScanlineStride();
	              rowData[i][0] = "Scanline stride";
	               rowData[i++][1] = Integer.toString(scanlineStride);
	              rowData[i][0] = "Pixel stride";
	              rowData[i++][1] = "N/A";
	          } else if ( sm  instanceof MultiPixelPackedSampleModel){
	              MultiPixelPackedSampleModel  msm = (MultiPixelPackedSampleModel)sm;
	               scanlineStride = msm.getScanlineStride();
	               rowData[i][0] = "Scanline stride";
	               rowData[i++][1] = Integer.toString(scanlineStride);
	              int pixelBitStride = msm.getPixelBitStride();
	              rowData[i][0] = "Pixel bit stride";
	              rowData[i++][1] = Integer.toString(pixelBitStride);;
	           }
	        }
	       return rowData;
	   }

	   public static String getColorSpaceAsText(int cs){
	      switch(cs) {
	         case ColorSpace.CS_GRAY:
	           return " Gray";
	         case ColorSpace.CS_PYCC:
	           return " Photo YCC";
	         case ColorSpace.CS_sRGB:
	           return " sRGB ";
	         case ColorSpace.CS_LINEAR_RGB:
	           return " Linea RGB";
	         case ColorSpace.CS_CIEXYZ:
	           return " CIEXYZ ";
	         case ColorSpace.TYPE_GRAY:
	           return " Gray";
	         case ColorSpace.TYPE_CMYK:
	           return " CMYK";
	         case ColorSpace.TYPE_RGB:
	           return " RGB ";
	         case ColorSpace.TYPE_HSV:
	           return " HSV";
	         case ColorSpace.TYPE_XYZ:
	           return "XYZ ";
	         default:
	           return " Unknown";
	        }
	   }

	   public static String getDataTypeAsText(int dttype){
	      switch(dttype) {
	         case DataBuffer.TYPE_BYTE:
	           return " Byte";
	         case DataBuffer.TYPE_SHORT:
	           return " Short";
	         case DataBuffer.TYPE_USHORT:
	           return " Unsigned short";
	         case DataBuffer.TYPE_INT:
	           return " int";
	         case DataBuffer.TYPE_FLOAT:
	           return " Float";
	         case DataBuffer.TYPE_DOUBLE:
	           return " Double";
	         case DataBuffer.TYPE_UNDEFINED:
	           return " Undefined";
	         default:
	           return " Unknown";
	        }
	   }

	   public static String getColorModelAsText(int cmtype){
	      switch(cmtype) {
	         case DIRECT:
	           return " Direct";
	         case COMPONENT:
	           return " Component";
	         case INDEX:
	           return " Indexed";
	         default:
	           return " Unknown";
	      }
	   }

	  public static String getSampleModelAsText(int smtype){
	      switch(smtype) {
	         case PIXEL_INTERLEAVED:
	           return " Pixel interleaved";
	         case BANDED:
	           return " Banded";
	         case SINGLE_PIXEL_PACKED:
	           return "Single pixel packed";
	         case MULTI_PIXEL_PACKED:
	           return "Muti pixel packed";
	         case COMPONENT_SAMPLE:
	           return " Component ";
	         default:
	           return " Unknown";
	        }
	   }

	   public static int getColorModelType(ColorModel cm) {
	      int type = DIRECT;
	      if(cm instanceof ComponentColorModel){
	         type = COMPONENT;
	         //System.out.println("Component color model");
	      }
	      if(cm instanceof DirectColorModel){
	         type =  DIRECT;
	         //System.out.println("Direct color model");
	      }
	      if(cm instanceof IndexColorModel) {
	         type = INDEX;
	         //System.out.println("Indexed color model");
	      }
	      return type;
	   }

	    public static int getSampleModelType(SampleModel cm) {
	      int type = COMPONENT_SAMPLE;
	      if(cm instanceof ComponentSampleModel){
	         type = COMPONENT_SAMPLE;

	         //System.out.println("Component sample model");
	      }
	      if(cm instanceof  SinglePixelPackedSampleModel ){
	         type = SINGLE_PIXEL_PACKED;
	         //System.out.println("single pixel model");
	      }
	      if(cm instanceof MultiPixelPackedSampleModel) {
	         type = MULTI_PIXEL_PACKED;
	         //System.out.println("Multi sample model");
	      }

	      if(cm instanceof BandedSampleModel) {
	         type = BANDED;
	         //System.out.println("Banded sample model");
	      }

	      if(cm instanceof PixelInterleavedSampleModel) {
	         type = PIXEL_INTERLEAVED;
	         //System.out.println("Pixel interleaved sample model");
	      }

	      return type;
	   }


	   public static int[][] getRGBStats(ColorModel cm, int pixels[]){
	       if(pixels == null) return null;
	       int pix;

	       int max = Integer.MIN_VALUE;
	       int min = Integer.MAX_VALUE;

	       int[] pixelComps = {RED, GREEN, BLUE};
	       int stats[][] =  new int[pixelComps.length][3];
	       for(int j=0;j<pixelComps.length;j++){
	       int sum =0;
	       for(int i=0; i<pixels.length;i++){
	           switch(pixelComps[j]){
	               case RED:
	                  pix = cm.getRed(pixels[i]);
	                  break;
	               case GREEN:
	                  pix = cm.getGreen(pixels[i]);
	                  break;
	               case BLUE:
	                  pix = cm.getBlue(pixels[i]);
	                  break;
	               case ALPHA:
	                  pix = cm.getAlpha(pixels[i]);
	                  break;
	               default:
	                  pix =0;
	           }
	           if(pix > max) max = pix;
	           if(pix < min ) min = pix;
	           sum += pix;
	       }

	       double average = sum/pixels.length;
	       stats[j][0] = min; stats[j][1] = max; stats[j][2] = (int)average;
	       }
	       return stats;
	    }

	     public static int[][] getImageStats(BufferedImage img){
	       if(img == null) return null;
	       SampleModel sm = img.getSampleModel();
	       WritableRaster wr = img.getRaster();
	       DataBuffer db = wr.getDataBuffer();
	       ColorModel cm = img.getColorModel();
	       return ImageInfoUtil.getImageStats(sm, db, new Dimension(img.getWidth(), img.getHeight()));
	    }


	    /**
	      * @return a two dimensional array. First dimension is the component and second is the stats
	      **/
	    public static int[][] getImageStats(SampleModel sm, DataBuffer db, Dimension imageSize){
	       int imageWidth = imageSize.width;
	       int imageHeight = imageSize.height;
	       int pixel[][] = new int[imageHeight*imageWidth][];
	       for(int i=0;i<imageHeight;i++){
	           for(int j=0; j<imageWidth;j++) {
	               int pix[] = null;
	               pixel[i*imageWidth+j] =  sm.getPixel(j,i, pix, db);
	           }
	       }

	       int len = pixel[0].length;
	       int sum[] = new int[len];
	       int max[] = new int[len];
	       int min[] = new int[len];
	       int[][] imageStats = new int[len][3];
	       for(int j=0;j<len;j++) {
	           sum[j] =0;
	           max[j] = Integer.MIN_VALUE;
	           min[j] = Integer.MAX_VALUE;
	           for(int i=0;i<pixel.length;i++) {
	               int pix = pixel[i][j];
	               if(pix > max[j]) max[j] = pix;
	               if(pix < min[j] ) min[j] = pix;
	               sum[j] += pix;
	           }
	           //System.out.println("min = "+min[j]+ " max = "+max[j]+ " average = "+ sum[j]/(imageHeight*imageWidth));
	           imageStats[j][0] = min[j];
	           imageStats[j][1] = max[j];
	           imageStats[j][2] = sum[j]/(imageHeight*imageWidth);
	       }
	       return imageStats;
	    }

	    public static int[][] getPixelSamples(BufferedImage img) {
	       WritableRaster wr = img.getRaster();
	       Dimension size = new Dimension(img.getWidth(), img.getHeight());
	       return getPixelSamples(wr, size);
	    }

	    public static int[][] getPixelSamples(Raster raster, Dimension imageSize){
	       if((raster == null) || (imageSize ==null)) return null;
	       SampleModel sm = raster.getSampleModel();
	       DataBuffer db = raster.getDataBuffer();
	       int imageWidth = imageSize.width;
	       int imageHeight = imageSize.height;
	       int totalPix = imageHeight*imageWidth;
	       int sample[][] = new int[totalPix][];
	       for(int i=0;i<imageHeight;i++){
	           for(int j=0; j<imageWidth;j++) {
	               int pix[] = null;
	               sample[i*imageWidth+j] =  sm.getPixel(j,i, pix, db);
	           }
	       }
	       int pixel[][] = new int[sample[0].length][ totalPix];
	       for(int i=0; i<pixel.length;i++){
	           for(int j=0; j<totalPix;j++) {
	               pixel[i][j] = sample[j][i];
	           }
	       }
	       return pixel;
	    }

	     public static int[][] getPixelSamples(SampleModel sm, DataBuffer db, Dimension imageSize){
	       if((sm == null) ||(db == null) ||(imageSize ==null)) return null;
	       int imageWidth = imageSize.width;
	       int imageHeight = imageSize.height;
	       int totalPix = imageHeight*imageWidth;
	       int sample[][] = new int[totalPix][];
	       for(int i=0;i<imageHeight;i++){
	           for(int j=0; j<imageWidth;j++) {
	               int pix[] = null;
	               sample[i*imageWidth+j] =  sm.getPixel(j,i, pix, db);
	           }
	       }
	       int pixel[][] = new int[sample[0].length][ totalPix];
	       for(int i=0; i<pixel.length;i++){
	           for(int j=0; j<totalPix;j++) {
	               pixel[i][j] = sample[j][i];
	           }
	       }
	       return pixel;
	    }
}
